/**
 * 微盛微信小程序客户端开放数据SDK
 * author: royslg
 * DateTime: 2018-09-06
 *
 * 注：变量命名方式：小驼峰，通用缩写统一使用全部大写 如ID等
 */
import { setStorage, getStorage, setGlobalData, getGlobalData } from './ws-common-data-operation.js';

const constants = require('./constants.js');
const lib = require('./ws-common-lib.js');
const wxWork = require('./ws-wxwork.js');

function _getMode(mode) {
  if (mode && Number(mode) === 2) mode = 2;
  else mode = 1;

  return mode;
}

// 还技术债
function _getValueFromDebtUserInfo(key) {
  let userInfo = getStorage('userInfo');
  let openID = getStorage('OPENID') || getStorage('openid');
  if (key === 'openID') {
    return userInfo.openid || (userInfo.wxInfo && userInfo.wxInfo.openid) || openID;
  }

  if (key === 'wxInfo') {
    return userInfo.wxInfo;
  }
}

function _setValueToDebtUserInfo(key, value) {
  let userInfo = getStorage('userInfo');
  userInfo = userInfo || {};

  if (key === 'sessionID') {
    userInfo.sessionid = value;
    return setStorage('userInfo', userInfo);
  } else if (key === 'openID') {
    // TODO, to complete this;
    // userInfo = Object.assign(userInfo, value);
    if (userInfo.wxInfo) userInfo.wxInfo.openid = value;
    userInfo.openid = value;
    setStorage('userInfo', userInfo); // 兼容绝大部分的userInfo
    setStorage('OPENID', value); // 兼容微商城
    setStorage('openid', value); // 兼容其他
  }
}


// mode !== 2 && _setOpenID(session.data.data.openid);
// 访问后台框架统一的接口，获取openID和sessionid，需要Wx.login的code
function _requestOauthOpenData(code, mode) {
  return new Promise((resolve, reject) => {
    const systemInfo = wx.getSystemInfoSync();
    lib.request({
      url: 'auth/session/openid',
      data: {
        code,
        brand: systemInfo.brand,
        model: systemInfo.model,
      },
      cachetime: 0,
    }).then(session => {
      const openID = !session.data.errno ? session.data.data.openid : '';
      const sessionID = !session.data.errno ? session.data.data.sessionid : '';
      if (mode !== 2) {
        _setOpenID(openID);
        _setSessionID(sessionID);
      }
      if (session.data.data && session.data.data.isopenqywx && wxWork.isWxWork()) {
        wxWork.qyWXLogin();
      }

      // console.log('request openID & sessionID complete:', { openID, sessionID });
      resolve({ openID, sessionID });
    }, (e) => {
      console.log(constants.API_REQUEST_FAILED, 'auth/session/openid');
      // console.trace();
      reject(e);
    });
  });
}

// 内部接口请求，接收动态链接，业务逻辑自行处理接口返回值
function _sendRequest(arg) {
  return lib.request({
    url: arg.url,
    data: arg.data,
    cachetime: arg.cachetime || 0,
    method: arg.method,
  });
}

/**
 * 存储code
 * @param {String} value
 */
function _setCode(value) {
  setStorage('wsCode', value) || setGlobalData('wsCode', value);
}

/**
 * 获取openid 和 sessionID，依赖code
 * @param {Number} mode 1同步更新全局数据 2不更新仅返回全局数据
 * @return {promise}
 */
function _getOpenData(mode) {
  mode = _getMode(mode);

  // TODO, complete catch
  return _wxLogin().then(code => {
    return _requestOauthOpenData(code, mode);
  });
}

/**
 * 存储openid
 * @param {String} value
 */
function _setOpenID(value) {
  setStorage('wsOpenID', value) || setGlobalData('wsOpenID', value);

  _setValueToDebtUserInfo('openID', value);
}

/**
 * 存储session_key
 * @param {String} value
 */
function _setSessionID(value) {
  setStorage('wsSessionID', value) || setGlobalData('wsSessionID', value);

  // 兼容旧框架
  _setValueToDebtUserInfo('sessionID', value);
}

/**
 * 获取ueserInfo
 * @param {Number} mode 1同步更新全局数据 2不更新仅返回全局数据
 * @return {promise}
 */
function _getUserInfo(mode) {
  return new Promise((resolve, reject) => {
    _getSetting('scope.userInfo').then((res) => {
      if (!res) reject(new Error(false));
      res && wx.getUserInfo({
        success: res => {
          mode !== 2 && _setUserInfo(res.userInfo);
          resolve(res.userInfo);
        },
        fail: err => {
          console.log(constants.OFFICAL_API_REQUEST_FAILED, 'wx.getUserInfo');
          // console.trace();
          reject(err);
        },
      });
    }).catch(err => {
      // 未授权，业务代码获取reject自行拉起button组件授权
      reject(err);
    });
  });
}

/**
 * 设置ueserInfo
 * @param {object} value
 */
function _setUserInfo(value) {
  setStorage('wsUserInfo', value) || setGlobalData('wsUserInfo', value);
}

/**
 * 简单封装wx.login接口
 * @param  {Object} opt
 * @return {promise}
 */
function _wxLogin(opt) {
  return new Promise((resolve, reject) => {
    wx.login({
      timeout: (opt && opt.timeout) || 2000,
      success: res => {
        res.code && (opt && opt.mode !== 2) && _setCode(res.code);
        res.code && resolve(res.code);
      },
      fail: err => {
        // TODO 处理超时情况
        console.log(constants.OFFICAL_API_REQUEST_FAILED, 'wx.login');
        // console.trace();
        reject(err);
      },

      complete: res => {
        // TODO
      },
    });
  });
}

/**
 * 状态判断内部函数:用户授权设置状态，是否在登录态状态等
 * @param  {String} scope
 * @return {promise}
 */
function _getSetting(scope) {
  return new Promise((resolve, reject) => {
    wx.getSetting({
      success: res => {
        // console.log('get wx setting ok:', res);
        resolve(res.authSetting[scope]);
      },
      fail: err => {
        console.log(constants.OFFICAL_API_REQUEST_FAILED, 'wx.getSetting');
        // console.trace();
        reject(err);
      },
    });
  });
}

/**
 * 是否登录状态，即从wx.login后续获取的session_key/sessionid是否过期。
 * @return {promise}
 */
function _isInSession() {
  return new Promise((resolve, reject) => {
    wx.checkSession({
      success: () => resolve(true),
      fail: () => reject(new Error(false)),
      complete: res => console.log('checkSession complete:', res),
    });
  });
}

// 暴露的公共接口
// 提供微信开放数据等数据的专属操作接口。
// 仅提供get操作，修改删除等危险操作设为私有，通过传参控制操作。
// 原则，从global data中获取，再从storage中获取，再走接口返回promise，具体业务代码自行判断。
// typeof [promise] === 'object'

/**
 * 获取opennid的公共接口，openID对同一小程序不变，所以无需判断会话是否过期
 * @param  {Object} opt 请求object参数，包括数据处理模式： 1同步更新全局数据，2仅获取
 * @return {promise}
 */
function getOpenID(opt = {}) {
  return new Promise((resolve, reject) => {
    const openID = getGlobalData('wsOpenID') || getStorage('wsOpenID') || _getValueFromDebtUserInfo('openID');
    if (openID) {
      // console.log('get openID from local data:', openID);
      resolve(openID);
    } else {
      _getOpenData(opt.mode).then(data => resolve(data.openID));
    }
  });
}

/**
 * 获取框架sessionID的公共接口，要判断会话是否过期。单独此接口的场景比较少，暂时用不到，后期优化
 * @param  {Object} opt 请求object参数，包括数据处理模式： 1同步更新全局数据，2仅获取
 * @return {promise}
 */
function getSessionID(opt = {}) {
  return new Promise((resolve, reject) => {
    _isInSession().then(() => {
      const sessionID = getGlobalData('wsSessionID') || getStorage('wsSessionID');
      if (sessionID) {
        // console.log('get sessionID from local data:', sessionID);
        resolve(sessionID);
      } else {
        _getOpenData(opt.mode).then(data => resolve(data.sessionID));
      }
    }).catch(() => {
      _getOpenData(opt.mode).then(data => resolve(data.sessionID));
    });
  });
}

/**
 * 获取userInfo基础信息的公共接口，数据格式应和微信默认一样，详见：https://developers.weixin.qq.com/miniprogram/dev/api/open-api/user-info/UserInfo.html
 * @param  {Object} opt 请求object参数，包括数据处理模式： 1同步更新全局数据，2仅获取
 * @return {promise} object | string | false
 */
function getUserInfo(opt = {}) {
  return new Promise((resolve, reject) => {
    let userInfoFromDebt = _getValueFromDebtUserInfo('wxInfo');
    // 如果是false，说明用户信息未授权
    let userInfo = getStorage('wsUserInfo') || getGlobalData('wsUserInfo') || userInfoFromDebt || _getUserInfo(opt.mode);
    resolve(userInfo);
    // else .then(res => resolve(res)).catch(() => reject(new Error(false)));
  });
}

// 获取带有敏感信息（openID等，需通过后台解密返回）的userInfo信息
// 传后端所需的四个签名验证数据，返回后各自业务逻辑自行处理返回值
function getUserInfoWidthCredentials(arg) {
  const systemInfo = wx.getSystemInfoSync();
  let options = {
    url: 'auth/session/userinfo',
    data: {
      signature: arg.signature || arg.detail.signature,
      rawData: arg.rawData || arg.detail.rawData,
      iv: arg.iv || arg.detail.iv,
      encryptedData: arg.encryptedData || arg.detail.encryptedData,
      brand: systemInfo.brand,
      model: systemInfo.model,
    },
    method: 'POST',
    cachetime: arg.cachetime, // 单位：秒
  };

  if ((!arg.signature && !arg.detail.signature) || (!arg.iv && !arg.detail.iv) || (!arg.encryptedData && !arg.detail.encryptedData)) {
    return new Promise((resolve, reject) => {
      // console.log('in getUserInfoWidthCredentials');
      reject(new Error('缺少必要的参数'));
    });
  }
  return _isInSession().then(() => {
    return _sendRequest(options);
  }).catch(() => {
    return _getOpenData(1).then(openData => {
      return _sendRequest(options);
    });
  });
}

// 获取电话号码，需后端解密
/*
  @param {Object} url: 包括接口请求地址（各业务逻辑请求地址不同），openid: 用户openID（非必须）, detail：加密数据相关字段数据, method
 */
function getPhoneNumber(arg) {
  // TODO， 对参数进行判断处理
  return _isInSession().then(() => {
    return _sendRequest({
      url: arg.url,
      method: arg.method,
      data: {
        encryptedData: arg.detail.encryptedData,
        iv: arg.detail.iv,
        openid: arg.openid,
      },
    });
  }).catch(() => {
    return _getOpenData(1).then(openData => {
      return _sendRequest({
        url: arg.url,
        method: arg.method,
        data: {
          encryptedData: arg.detail.encryptedData,
          iv: arg.detail.iv,
          openid: openData.openID,
        },
      });
    });
  });
}

/**
 * 其余公共接口
 * 做登录操作，在后台存/刷新session_key/sessionid：访问一遍auth/session/openid的接口
 * @return {promise} promise 里返回包含 openID 和 sessionID 的 object
 */
function doLogin() {
  return _getOpenData(1);
}

// TODO
// function getUnionID(opt) {
// }

// TODO，针对微商城等特殊模块，是否统一处理？


export {
  getOpenID,
  getSessionID,
  getUserInfo,
  getUserInfoWidthCredentials,
  getPhoneNumber,
  doLogin
};
